﻿using System.Reflection;
using System.Windows;
using GalaSoft.MvvmLight.Messaging;
using MetaVideoEditorEvolved.Helper;
using mveEngine;

namespace MetaVideoEditorEvolved.ViewModel
{
	using System;
	using System.ComponentModel;
	using System.Globalization;
	using System.IO;
	using GalaSoft.MvvmLight;
	using GalaSoft.MvvmLight.Command;
	using MetaVideoEditorEvolved.UI;
	using System.Linq;

	public class SplashScreenVM : ViewModelBase
	{
		private BackgroundWorker worker;

		private int steps;

		private int totalSteps = 100;

		private string statusText;
		
		private string currentVersion;

		private bool isDetailNeeded;

		private bool isRebuild;

		private int totalItemsCache;

		private int loadedItemCache;
		
		private MetaVideoEditorEvolved.UI.Entity.KernelEntity uiKernel;

		private MetaVideoEditorEvolved.Helper.Dispatcher dispatcher = new Helper.Dispatcher();

		public RelayCommand LoadedCommand
		{
			get;
			set;
		}
		
		public MetaVideoEditorEvolved.UI.Entity.KernelEntity UiKernel
		{
			get
			{
				return this.uiKernel;
			}

			set
			{
				this.uiKernel = value;
				this.RaisePropertyChanged("UiKernel");
			}
		}

		public bool IsRebuild
		{
			get
			{
				return this.isRebuild;
			}

			set
			{
				this.isRebuild = value;
				this.RaisePropertyChanged("IsRebuild");
			}
		}

		public bool IsDetailNeeded
		{
			get
			{
				return this.isDetailNeeded;
			}

			set
			{
				this.isDetailNeeded = value;
				this.RaisePropertyChanged("IsDetailNeeded");
			}
		}

		public int LoadedItemCache
		{
			get
			{
				return this.loadedItemCache;
			}

			set
			{
				this.loadedItemCache = value;
				this.RaisePropertyChanged("LoadedItemCache");
			}
		}

		public int TotalItemsCache
		{
			get
			{
				return this.totalItemsCache;
			}

			set
			{
				this.totalItemsCache = value;
				this.RaisePropertyChanged("TotalItemsCache");
			}
		}
		
		public string CurrentVersion
		{
			get
			{
				return this.currentVersion;
			}

			set
			{
				this.currentVersion = value;
				this.RaisePropertyChanged("CurrentVersion");
			}
		}

		public int Steps
		{
			get
			{
				return this.steps;
			}

			set
			{
				this.steps = value;
				this.RaisePropertyChanged("Steps");
			}
		}

		public int TotalSteps
		{
			get
			{
				return this.totalSteps;
			}

			set
			{
				this.totalSteps = value;
				this.RaisePropertyChanged("TotalSteps");
			}
		}

		public string StatusText
		{
			get
			{
				return this.statusText;
			}

			set
			{
				this.statusText = value;
				this.RaisePropertyChanged("StatusText");
			}
		}

		public SplashScreenVM(bool isRebuild)
		{
			this.currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
			
			var config = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(true).First((att)=>
			                                                                                               {
			                                                                                               	return att is System.Reflection.AssemblyConfigurationAttribute;
			                                                                                               }) as System.Reflection.AssemblyConfigurationAttribute;
			
			this.currentVersion += " " + config.Configuration;
			
			this.isRebuild = isRebuild;

			if (!this.isRebuild)
			{
				Tracer.TracerInstance.Level = (TracerLevel) Enum.Parse(typeof(TracerLevel), Config.Instance.TraceLevel);
				Tracer.TracerInstance.FileName = "Application";
			}
			
			this.LoadedCommand = new RelayCommand(() =>
			                                      {
			                                      	this.Loaded();
			                                      });
		}

		protected virtual MetaVideoEditorEvolved.Helper.IKernelHelper CreateKernelHelper()
		{
			return new Helper.KernelHelper();
		}

		protected virtual Data.IFileManager CreateFileManager()
		{
			return new Data.FileManager();
		}

		private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			if (e.UserState != null && e.UserState is UI.Entity.MediaItemBaseEntity==false && (e.UserState.ToString() != "CACHE" || (this.IsRebuild && e.ProgressPercentage != 50)))
			{
				this.Steps = e.ProgressPercentage;
				this.StatusText = e.UserState.ToString();

				if (e.ProgressPercentage == 50 || this.IsRebuild)
				{
					if(!this.IsDetailNeeded)
					{
						MetaVideoEditorEvolved.UI.KernelSessionManager.SessionInstance.RealKernel = mveEngine.Kernel.Instance;
						this.UiKernel = MetaVideoEditorEvolved.UI.KernelSessionManager.SessionInstance.KernelUiEntity;
						this.IsDetailNeeded = true;
					}
				}
			}
			else
			{
				if (this.UiKernel.FlatListOfMediaItems.Count != 0 && this.LoadedItemCache != this.UiKernel.FlatListOfMediaItems.Count)
				{
					this.LoadedItemCache++;
				}

				if (this.UiKernel.FlatListOfMediaItems.Count == this.LoadedItemCache)
				{
					this.Steps++;
				}

				if (!this.IsRebuild)
				{
					this.StatusText = string.Format(Properties.Resources.Form_SplashScreen_LoadCache, this.LoadedItemCache.ToString(CultureInfo.InvariantCulture), this.UiKernel.FlatListOfMediaItems.Count.ToString(CultureInfo.InvariantCulture));
				}
				else
				{
					if (e.ProgressPercentage != 100)
					{
						this.Steps = 50;
						this.StatusText = string.Format(Properties.Resources.Form_SplashScreen_CreateCache, ((UI.Entity.VideoMediaElement)e.UserState).Title + " " + this.LoadedItemCache.ToString(CultureInfo.InvariantCulture) + "/" + this.UiKernel.FlatListOfMediaItems.Count.ToString(CultureInfo.InvariantCulture));
					}
					else
					{
						this.Steps = 100;
						this.StatusText = Properties.Resources.Form_SplashScreen_RefreshTreeview;
					}
				}
			}
		}

		private void worker_DoWork(object sender, DoWorkEventArgs e)
		{
			try
			{
				if (!this.IsRebuild)
				{
					this.worker.ReportProgress(0, Properties.Resources.Form_SplashScreen_LoadingKernel);
					this.CreateKernelHelper().InitKernel();

					this.worker.ReportProgress(50, string.Format(Properties.Resources.Form_SplashScreen_LoadCache, "0", "..."));
					
					// Wait uiKernel is set
					while (this.UiKernel==null) {
						System.Threading.Thread.Sleep(100);
					}

					this.CreateKernelHelper().ClearCheckedItems();

					if (mveEngine.Config.Instance.IsFirstRun)
					{
						this.UiKernel = null;
						this.IsDetailNeeded = false;
						this.dispatcher.Dispatcher.Invoke(new Action(() =>
						                                             {
						                                             	new ConfigWizard()
						                                             	{
						                                             		DataContext = new ConfigWizardVM()
						                                             	}.ShowDialog();
						                                             }));

						this.CreateKernelHelper().ReloadItemCollection();
						this.CreateKernelHelper().ClearCheckedItems();
						this.worker.ReportProgress(50, string.Format(Properties.Resources.Form_SplashScreen_LoadCache, "0", "..."));
						
						// Wait uiKernel is set
						while (this.UiKernel==null) {
							System.Threading.Thread.Sleep(100);
						}
					}
					
					// 0 item in cache
					if (this.UiKernel.FlatListOfMediaItems.Count == 0)
					{
						this.worker.ReportProgress(0, "CACHE");
					}

					// Test cache version
					var version = this.UiKernel.Cache.DetectedVersion;
					Tracer.TracerInstance.TraceInformation("Old cache version: " + version.ToString());

					if (version != this.UiKernel.Cache.SupportedVersion)
					{
						Tracer.TracerInstance.TraceInformation("Supported cache version is different, the cache will be deleted");
						this.CreateKernelHelper().ClearCache();
						mveEngine.Kernel.SetSupportedVersionInCache();
					}

					// Load items from cache
					foreach (MetaVideoEditorEvolved.UI.Entity.FileMediaElement item in this.UiKernel.FlatListOfMediaItems)
					{
						string path = Path.Combine(mveEngine.ApplicationPaths.AppCachePath, item.Id.ToString());
						if (this.CreateFileManager().Exists(path))
						{
							try
							{
								var i = this.CreateKernelHelper().LoadItemFromCache(item.Id.ToString());
								this.CreateKernelHelper().CopyDataFromCache(mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString()), i);
								i.CopyToMediaUiEntity(item);
							}
							catch (Exception ex)
							{
								Tracer.TracerInstance.TraceError("Error loading cache for " + path, ex);

								// In case of error load from local and create new cache item
								try
								{
									this.CreateKernelHelper().LoadLocalDataAndSaveToCache(mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString()));
								}
								catch (Exception exLocal)
								{
									Tracer.TracerInstance.TraceError("Error loading from local data" + item.Id, exLocal);
								}

								continue;
							}
							finally
							{
								this.worker.ReportProgress(0, "CACHE");
							}
						}
						else
						{
							try
							{
								// Load from local data only if cache doesn't exist
								var mveItem = mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString());
								this.CreateKernelHelper().LoadLocalDataAndSaveToCache(mveItem);
								mveItem.CopyToMediaUiEntity(item);
							}
							catch (Exception exLocal)
							{
								Tracer.TracerInstance.TraceError("Error loading from local data" + item.Id, exLocal);
							}
							finally
							{
								this.worker.ReportProgress(0, "CACHE");
							}
						}
					}

					this.worker.ReportProgress(100);
				}
				else
				{
					this.CreateKernelHelper().ClearCache();

					this.CreateKernelHelper().ReloadItemCollection();
					this.CreateKernelHelper().ClearCheckedItems();

					mveEngine.Item i = null;
					
					this.worker.ReportProgress(0, Properties.Resources.Form_SplashScreen_DeletingCache);

					// Wait uiKernel is set
					while (this.UiKernel==null) {
						System.Threading.Thread.Sleep(100);
					}

					foreach (MetaVideoEditorEvolved.UI.Entity.FileMediaElement item in this.UiKernel.FlatListOfMediaItems)
					{
						string path = System.IO.Path.Combine(mveEngine.ApplicationPaths.AppCachePath, item.Id.ToString());
						if (this.CreateFileManager().Exists(path))
						{
							try
							{
								i = this.CreateKernelHelper().LoadItemFromCache(item.Id.ToString());
								var mveItem = mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString());
								this.CreateKernelHelper().UpdateLocalItemWithOptionsFromPlugin(mveItem, i);
								mveItem.CopyToMediaUiEntity(item);
							}
							catch (Exception ex)
							{
								Tracer.TracerInstance.TraceError("Error loading cache for " + path, ex);

								// In case of error load from local and create new cache item
								try
								{
									var mveItem = mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString());
									this.CreateKernelHelper().LoadLocalDataAndSaveToCache(mveItem);
									mveItem.CopyToMediaUiEntity(item);
								}
								catch (Exception exLocal)
								{

									Tracer.TracerInstance.TraceError("Error loading from local data" + item.Id, exLocal);
								}

								continue;
							}
							finally
							{
								this.worker.ReportProgress(0, i);
							}
						}
						else
						{
							var mveItem = mveEngine.Kernel.Instance.ItemCollection.FindById(item.Id.ToString());
							this.CreateKernelHelper().LoadLocalDataAndSaveToCache(mveItem);
							mveItem.CopyToMediaUiEntity(item);
							this.worker.ReportProgress(0, item);
						}
					}

					this.worker.ReportProgress(100);

					//TODO : need update file ->see load data
					this.CreateKernelHelper().RefreshData();
				}
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError("Error in splash screnn vm", ex);
				throw;
			}

		}

		private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			if(e.Error==null)
			{
				this.Steps = this.TotalSteps;

				if (!this.IsRebuild)
				{
					Messenger.Default.Send(new Messages.OpenWindowMessage() { WindowToOpen = Messages.WindowType.MainWindow });
				}

				Messenger.Default.Send<Messages.CloseMessage>(new Messages.CloseMessage() { WindowToClose = Messages.WindowType.SplashScreen });
			}
			else
			{
				MessageBox.Show(e.Error.ToString(),"Error",MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}

		private void Loaded()
		{
			if (this.worker == null)
			{
				// check if it is a stable release
				var config = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(true).First((att)=>
				                                                                                               {
				                                                                                               	return att is System.Reflection.AssemblyConfigurationAttribute;
				                                                                                               }) as System.Reflection.AssemblyConfigurationAttribute;
				
				if (!string.IsNullOrEmpty(config.Configuration) && config.Configuration.ToLower()!="stable") {
					MessageBox.Show(Properties.Resources.Global_Messages_BetaWarning, Properties.Resources.Global_Messages_MsgBoxTitle, MessageBoxButton.OK, MessageBoxImage.Warning);
				}
				
				this.worker = new BackgroundWorker();
				this.worker.WorkerReportsProgress = true;
				this.worker.DoWork += new DoWorkEventHandler(worker_DoWork);
				this.worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
				this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

				this.worker.RunWorkerAsync();
			}
		}
	}
}
